<?php

defined('BASEPATH') or die('forbidden');

/**
 * EMAIL类
 * @author  Karson
 * @name    email.php
 * @since   2013-2-23 16:02:26
 */
class Email {

    private $smtpServer = 'smtp.163.com';
    private $port = '25';
    private $timeout = '15';
    private $username = '';
    private $password = '';
    private $newline = "\r\n";
    private $localdomain = 'localhost';
    private $charset = 'utf-8';
    private $contentTransferEncoding = false;
    private $smtpConnect = false;
    public $to = false;  //收件人
    public $cc = false;  //抄送
    public $bcc = false;  //密送
    public $rcpt_to = array();
    public $subject = false;
    public $message = false;
    public $headers = false;
    public $logArray = array();
    public $Error = '';

    public function __construct() {
        $framework = &get_instance('controller');
        $this->config = $framework->config;
        $this->smtpServer = $this->config['email']['smtp_server'];
        $this->port = $this->config['email']['port'];
        $this->username = $this->config['email']['username'];
        $this->password = $this->config['email']['password'];
    }

    /**
     * 设置主题
     * @param string $str 邮件主题
     */
    function subject($str) {
        $this->subject = $str;
    }

    /**
     * 设置内容
     * @param string $str 内容
     */
    function message($str) {
        $this->message = $str;
    }

    /**
     * 设置收件人
     * @param mixed $str 收件人邮箱 可为字符串或数组
     */
    function to($str) {
        if (!is_array($this->to)) {
            if (is_email($this->to)) {
                $this->to = array($this->to);
            } else {
                $this->to = array();
            }
        }
        if (is_email($str)) {
            $this->to[] = $str;
        } else if (is_array($str)) {
            $this->to = array_merge($this->to, $str);
        }
    }

    /**
     * 设置抄送收件人
     * @param mixed $str 收件人邮箱 可为字符串或数组
     */
    function cc($str) {
        if (!is_array($this->cc)) {
            if (is_email($this->cc)) {
                $this->cc = array($this->cc);
            } else {
                $this->cc = array();
            }
        }
        if (is_email($str)) {
            $this->cc[] = $str;
        } else if (is_array($str)) {
            $this->cc = array_merge($this->cc, $str);
        }
    }

    /**
     * 设置密送收件人
     * @param mixed $str 收件人邮箱 可为字符串或数组
     */
    function bcc($str) {
        if (!is_array($this->bcc)) {
            if (is_email($this->bcc)) {
                $this->bcc = array($this->bcc);
            } else {
                $this->bcc = array();
            }
        }
        if (is_email($str)) {
            $this->bcc[] = $str;
        } else if (is_array($str)) {
            $this->bcc = array_merge($this->bcc, $str);
        }
    }

    private function Connect2Server() {
        // 连接服务器
        $this->smtpConnect = @fsockopen($this->smtpServer, $this->port, $errno, $error, $this->timeout);
        if (!is_resource($this->smtpConnect))
            return false;
        $this->logArray['CONNECT_RESPONSE'] = $this->readResponse();
        $this->logArray['connection'] = "Connection accepted: " . $this->smtpConnect;
        // 发送Hello程式
        $this->sendCommand("EHLO $this->localdomain");
        $this->logArray['EHLO'] = $this->readResponse();
        // 验证登录
        $this->sendCommand('AUTH LOGIN');
        $this->logArray['AUTH_REQUEST'] = $this->readResponse();
        // 发送用户名
        $this->sendCommand(base64_encode($this->username));
        $this->logArray['REQUEST_USER'] = $this->readResponse();
        // 发送密码
        $this->sendCommand(base64_encode($this->password));
        $this->logArray['REQUEST_PASSWD'] = $this->readResponse();
        // 判断密码是否出错
        if (substr($this->logArray['REQUEST_PASSWD'], 0, 3) != '235') {
            $this->Error .= 'Authorization error! ' . $this->logArray['REQUEST_PASSWD'] . $this->newline;
            return false;
        }
        // 发件人地址
        $this->sendCommand("MAIL FROM: <{$this->username}>");
        $this->logArray['MAIL_FROM_RESPONSE'] = $this->readResponse();
        if (substr($this->logArray['MAIL_FROM_RESPONSE'], 0, 3) != '250') {
            $this->Error .= 'Mistake in sender\'s address! ' . $this->logArray['MAIL_FROM_RESPONSE'] . $this->newline;
            return false;
        }
        // 收件人地址
        foreach ($this->rcpt_to as $i => $j) {
            $this->sendCommand("RCPT TO: <{$j}>");
        }
        $this->logArray['RCPT_TO_RESPONCE'] = $this->readResponse();
        if (substr($this->logArray['RCPT_TO_RESPONCE'], 0, 3) != '250') {
            $this->Error .= 'Mistake in reciepent address! ' . $this->logArray['RCPT_TO_RESPONCE'] . $this->newline;
        }
        // 发送数据到服务器
        $this->sendCommand('DATA');
        $this->logArray['DATA_RESPONSE'] = $this->readResponse();
        // 发送信息到收件人
        if (!$this->sendMail())
            return false;
        // 发送关闭
        $this->sendCommand('QUIT');
        $this->logArray['QUIT_RESPONSE'] = $this->readResponse();
        // 关闭SMTP连接
        fclose($this->smtpConnect);
        return true;
    }

    function send($to = null, $subject = null, $message = null) {
        if (!is_null($to))
            $this->to($to);
        if (!is_null($subject))
            $this->subject($subject);
        if (!is_null($message))
            $this->message($message);

        $this->tranReceiver();
        if (count($this->rcpt_to) <= 0)
            return false;
        if (!$this->Connect2Server()) {
            return false;
        } else {
            return true;
        }
    }

    function tranReceiver() {
        if (!is_array($this->to)) {
            $this->to = array($this->to);
        } else if (!$this->to) {
            $this->to = array();
        }
        if (is_array($this->cc)) {
            $this->rcpt_to = array_merge($this->to, $this->cc);
        } else if ($this->cc) {
            $this->rcpt_to = array_merge($this->to, array($this->cc));
        } else {
            $this->rcpt_to = $this->to;
        }
        if (is_array($this->bcc)) {
            $this->rcpt_to = array_merge($this->rcpt_to, $this->bcc);
        } else if ($this->bcc) {
            $this->rcpt_to = array_merge($this->rcpt_to, array($this->bcc));
        }
    }

    // 发送邮件
    private function sendMail() {
        $this->sendHeaders();
        $this->sendCommand($this->message);
        $this->sendCommand('.');
        if (count($this->rcpt_to) == 1) {
            $this->logArray['SEND_DATA_RESPONSE'] = $this->readResponse();
            if (substr($this->logArray['SEND_DATA_RESPONSE'], 0, 3) != '250') {
                $this->Error .= 'Mistake in sending data! ' . $this->logArray['SEND_DATA_RESPONSE'] . $this->newline;
                return false;
            }
        }
        return true;
    }

    // 读取返回状态
    private function readResponse() {
        $data = "";
        while ($str = fgets($this->smtpConnect, 4096)) {
            $data .= $str;
            if (substr($str, 3, 1) == " ")
                break;
        }
        return $data;
    }

    // 发送命令
    private function sendCommand($string) {
        fputs($this->smtpConnect, $string . $this->newline);
        return;
    }

    // 发送头部信息
    private function sendHeaders() {
        $this->sendCommand("Date: " . date("r"));
        $this->sendCommand("From: {$this->config['sitename']}<$this->username>");
        $this->sendCommand("Reply-To: <service@songyouhui.com>");
        $to_user = count($this->rcpt_to) > 1 ? "" : $this->rcpt_to[0];
        $this->sendCommand("To: <{$to_user}>");
        if ($this->cc && is_array($this->cc))
            $this->sendCommand("cc: <" . implode(',', $this->cc) . ">");
        if ($this->bcc && is_array($this->bcc))
            $this->sendCommand("Bcc: <" . implode(',', $this->bcc) . ">");
        $this->sendCommand("Subject: =?UTF-8?B?" . base64_encode($this->subject) . "?=");
        $this->sendCommand("MIME-Version: 1.0");
        $this->sendCommand("Content-Type: text/html; charset=$this->charset");
        if ($this->contentTransferEncoding)
            $this->sendCommand("Content-Transfer-Encoding: $this->contentTransferEncoding");
        $this->sendCommand($this->newline);
        return;
    }

    public function __destruct() {
        if (is_resource($this->smtpConnect))
            fclose($this->smtpConnect);
    }

}